# This is a sample Python script.
import argparse
import os
import re
from datetime import timedelta
import pandas as pd

from util.constants import ANALYSE_END_TIME, ANALYSE_START_TIME, POLICY_ALONE

# 找rtc最相关的wakeup alarm
all_attri_num = pd.DataFrame()


def parse_time(time_str):
    h_match = re.search(r'(?P<hour>\d+)h\d+', time_str)
    m_match = re.search(r'(?P<minute>\d+)m\d+', time_str)
    s_match = re.search(r'(?P<second>\d+)s\d+', time_str)
    ms_match = re.search(r'(?P<millisecond>\d+)ms', time_str)

    h = int(h_match.group('hour')) if h_match else 0
    m = int(m_match.group('minute')) if m_match else 0
    s = int(s_match.group('second')) if s_match else 0
    ms = int(ms_match.group('millisecond')) if ms_match else 0

    total_ms = h * 60 * 60 * 1000 + m * 60 * 1000 + s * 1000 + ms
    if total_ms == 0:
        return None
    else:
        return total_ms


def get_time(time_str):
    h_match = re.search(r'(?P<hour>\d+)h\d+', time_str)
    m_match = re.search(r'(?P<minute>\d+)m\d+', time_str)
    s_match = re.search(r'(?P<second>\d+)s\d+', time_str)
    ms_match = re.search(r'(?P<millisecond>\d+)ms', time_str)

    h = int(h_match.group('hour')) if h_match else 0
    m = int(m_match.group('minute')) if m_match else 0
    s = int(s_match.group('second')) if s_match else 0
    ms = int(ms_match.group('millisecond')) if ms_match else 0

    return timedelta(hours=int(h), minutes=int(m), seconds=int(s), milliseconds=int(ms))


def count_rtc_alarm( prev_timestamp, alarm_wakelock_timestamp, event):
    rtc_alarm_count = 0
    walarm_rtc_count = 0;
    if prev_timestamp is not None and '*walarm*:' in event and abs(
            prev_timestamp - alarm_wakelock_timestamp) < timedelta(
        seconds=0.5):
        rtc_alarm_count += 1

    if prev_timestamp is not None and '*alarm*:' in event and abs(
            prev_timestamp - alarm_wakelock_timestamp) < timedelta(
        seconds=0.5):
        walarm_rtc_count += 1

    return rtc_alarm_count, walarm_rtc_count;


# 处理每一行数据
def process_drain_line(line):
    screen_off_time = None
    screen_on_time = None
    charge_on_screen = None

    time = parse_time(line.split()[1])

    charge_search = re.search(r'charge=(\d+)', line)
    if charge_search:
        charge = int(charge_search.group(1))

    if "-screen" in line and screen_off_time is None:
        screen_off_time = time

    if "+screen" in line:
        screen_on_time = time
        charge_on_screen = charge


def parse_log_line(line):
    line = line.lstrip()
    match = re.search(r"(\d+ms).*?(wake_reason=0:\"\d+ qpnp_rtc_alarm\"|\"\*walarm\*:|\"\*alarm\*:).*",
                      line)
    if match:
        return (get_time(line), match.group(2))

    return None


def parse_log(path):
    f = open(path, encoding="ISO-8859-1")
    fileContent = f.readlines()
    f.close()
    return fileContent


def parse_timestamp(timestamp_str):
    m, s, ms = re.match(r"\+(\d+)m(\d+)s(\d+)ms", timestamp_str).groups()
    return timedelta(minutes=int(m), seconds=int(s), milliseconds=int(ms))


def is_less_than_half_second(t1, t2):
    return abs(t1 - t2) < timedelta(seconds=0.5)


def count_alarm_walarm(line):
    alarm = 0
    walarm = 0
    line = line.lstrip()
    if re.search(r':"\*walarm\*:', line):
        walarm = 1
    if re.search(r':"\*alarm\*:', line):
        alarm = 1
    return walarm, alarm


def get_rtc_alarm_num(line):
    match = re.search(r'.*qpnp_rtc_alarm:.*(\d+)\s*times', line)
    if match:
        qpnp_rtc_alarm = int(match.group(1))
    return qpnp_rtc_alarm


def count_event(content):
    battery_content_flag = False
    battery_content_out_flag = False

    wakeup_content_flag = False
    wakeup_content_out_flag = False
    # qpnp_rtc_alarm出现wakelock为walarm或者alarm次数
    walarm_rtc_count = 0
    alarm_rtc_count = 0

    # wakelock为walarm或者alarm次数
    w_count = 0
    a_count = 0

    cpu_count = 0
    ratio_count = 0
    cpu_runtime = 0
    cpu_start_time = 0

    atc_drain = 0
    duration = "0"
    qpnp_rtc_alarm = 0
    app_wakeup_alarm_num = 0

    prev_timestamp = None
    prev_alarm_timestamp = None

    # 计算真实耗电相关变量
    time = None
    charge_start = None
    charge_end = None
    charge_start_flag = True

    # time pattern

    app_wakeup_num = 0
    app_wakeup = pd.DataFrame()
    hardware = pd.DataFrame()

    for line in content:
        # Judge arrive batterystats paragraph
        line = line.lstrip()
        if not battery_content_flag:
            if re.search(r"Battery History .*", line):
                battery_content_flag = True

        # Judge out batterystats paragraph
        if (battery_content_out_flag is False) and (battery_content_flag is True):
            if re.search(r"Per-PID Stats:.*", line):
                battery_content_out_flag = True
                battery_content_flag = False

        # Judge arrive app status
        if (battery_content_out_flag is True) and (wakeup_content_flag is False):
            if re.search("Resource Power Manager Stats", line):
                wakeup_content_flag = True

        # Judge out app status
        if (wakeup_content_out_flag is False) and (wakeup_content_flag is True):
            if re.search("Total cpu time reads: ", line):
                wakeup_content_flag = False
                wakeup_content_out_flag = True

        if battery_content_flag:
            if line.split():
                tmp = parse_time(line.split()[0])
                if tmp is not None:
                    time = tmp

            # 计算真实耗电量
            charge_search = re.search(r'charge=(\d+)', line)

            # 统计硬件信息
            # CPU
            if '+running' in line:
                cpu_count += 1
                cpu_start_time = get_time(line)
            if '+wifi_radio' in line:
                ratio_count += 1
            if '-running' in line and cpu_runtime != 0:
                cpu_runtime += get_time(line) - cpu_start_time

            if charge_search:
                charge = int(charge_search.group(1))
                charge_time = time

                # 当灭屏后，flag标志位置为true，记录第一个charge
                if charge_start_flag and charge_time is not None and charge_time > ANALYSE_START_TIME:
                    charge_start_flag = False
                    charge_start = charge
                    charge_start_time = time

                # 指定时间进行分析
                if charge_time is not None and charge_time > ANALYSE_END_TIME:
                    charge_end = charge
                    charge_end_time = time
                    battery_content_flag = False
                    battery_content_out_flag = True

            # 统计qpnp_rtc_alarm
            parsed_line = parse_log_line(line)
            m,n=count_alarm_walarm(line)
            w_count += m
            a_count += n
            if parsed_line is None:
                # 匹配actual drain
                # Match the actual drain numbers and calculate the average
                drain_match = re.search(r'actual drain: (\d+\.?\d*)-(\d+\.?\d*)', line)
                if drain_match:
                    num1 = float(drain_match.group(1))
                    num2 = float(drain_match.group(2))
                    atc_drain = (num1 + num2) / 2

                # Match the durations
                duration_matches = re.search(r'idle:.*duration: ([\dhms\. ]+)', line)
                if duration_matches:
                    duration = duration_matches.group(1)
                continue

            # 匹配由rtc_alarm导致的唤醒
            timestamp, event = parsed_line
            if '*walarm*:' in event or '*alarm*:' in event:
                prev_alarm_timestamp = timestamp
            if 'wake_reason=0:"546 qpnp_rtc_alarm"' in event:
                qpnp_rtc_alarm += 1
                prev_timestamp = timestamp
                tmp_rtc_alarm,tmp_rtc_walarm = count_rtc_alarm(prev_timestamp,prev_alarm_timestamp, event);
                walarm_rtc_count += tmp_rtc_walarm
                alarm_rtc_count += tmp_rtc_alarm

            tmp_rtc_alarm, tmp_rtc_walarm = count_rtc_alarm(prev_timestamp, prev_alarm_timestamp, event);
            walarm_rtc_count += tmp_rtc_walarm
            alarm_rtc_count += tmp_rtc_alarm



        if wakeup_content_flag:
            # 统计App wakeup alarm
            # if "Wakeup alarm *walarm*:" in line:
            # 根据apk名称统计
            app_name_pattern = re.search(r'Apk\s(.+?):',line)
            if app_name_pattern:
                if app_wakeup_num != 0:
                    app_wakeup[app_name] = attri_num
                app_wakeup_num = 0
                app_name = app_name_pattern.group(1)
            s_app_wakeup = re.search(r'Wakeup alarm \*walarm\*:(.+?):\s(\d+)\s+times', line)
            if s_app_wakeup:
                attri = s_app_wakeup.group((1))
                attri_num = int(s_app_wakeup.group((2)))
                app_wakeup_alarm_num += attri_num
                app_wakeup_num += attri_num
        if wakeup_content_out_flag :
            if app_wakeup_num != 0:
                app_wakeup[app_name] = attri_num
            break
            # TODO:统计不同应用的waekup alarm，找到与qpnp_rtc_alarm关系最大的那个

    print("App wakeup alarm："+str(app_wakeup_alarm_num))

    # 增加属性
    # app_wakeup["wakeup_alarm"] = app_wakeup_alarm_num
    # app_wakeup["qpnp_rtc_alarm"] = qpnp_rtc_alarm

    print("cpu "+str(cpu_count))


    # 将文件中的wakeup数量增加到全局变量中
    global all_attri_num
    all_attri_num = pd.concat([all_attri_num, hardware], axis=0, ignore_index=True)

    if charge_end == None:
        charge_end = charge
        charge_end_time = time
    total_hour = (charge_end_time - charge_start_time) / (60 * 60 * 1000)
    total_drain = charge_start - charge_end
    avg_drain = total_drain / total_hour
    return walarm_rtc_count + alarm_rtc_count, w_count + a_count,qpnp_rtc_alarm,atc_drain,duration,avg_drain,total_hour

def count_Walarm_Qpnp(path):
    fileContent = parse_log(path)
    walarm_alarm_rtc_count,w_a_count,rtc_count,actual_drain,duration,avg_drain,test_time = count_event(fileContent)
    # print("test duration:" + duration)
    print("average drain:" + f"{avg_drain:.2f}" )
    print("qpnp_rtc_alarm:" + f"{rtc_count/test_time:.2f}" + "(count/hr)")
    # print("actual drain:" + f"{actual_drain:.2f}")
    print("walarm&rtc_alarm Count+alarm&rtc_alarm Count:" + f"{walarm_alarm_rtc_count/test_time:.2f}"+ "(count/hr)")
    print("alarm Count + walarm Count:" +f"{w_a_count/test_time:.2f}"+ "(count/hr)" )
    print("test time:" + str(test_time) + "h"+ "\n")

def analyse_rtc_alarm():
    global all_attri_num


def main():
    # 解析输入参数
    parser = argparse.ArgumentParser(
        prog='Battery consumer analyse tools',
        description='Tools for analyse battery consume',
        epilog='Copyright(r), 2023' # 说明信息
    )

    parser.add_argument('--mode',default="ALONE")
    parser.add_argument('--path',default="batteryStats/Pixel/Expriment/replay/v0.1")

if __name__ == '__main__':
    policy = "ALONE"
    if policy == "ALONE":
        filePath = "data/batteryStats/Pixel/Expriment/AOSP13/replay/v0.1"
        env=["alarmTrigger","realEnv","imitate_test",""]
        bugPolicy = [env[3]]
        for i in bugPolicy:
            print("********************* policy:"+i + " ************************")
            tmpPath = os.path.join(filePath,i)
            for file_name in os.listdir(tmpPath):
                print(file_name + ": ")
                count_Walarm_Qpnp(os.path.join(tmpPath, file_name))
    else:
        # 可选参数flight 、 wifi 、lte
        network_pattern = "wifi"
        # fullAlign对应完整的预测模块，align对应部分预测模块，paper对应对比论文，origin对应原生
        strategies_list = ["fullAlign","fullAlign","paper","origin"]
        data_path = "data/batteryStats/Pixel/v0.1/alarmTrigger"

        # 将batterystats的txt文件放入下列路径中
        fullAlign_path = os.path.join(data_path, network_pattern, strategies_list[0])
        align_path = os.path.join(data_path, network_pattern, strategies_list[1])
        paper_path = os.path.join(data_path, network_pattern, strategies_list[2])
        origin_path = os.path.join(data_path, network_pattern, strategies_list[3])
        # align_path = "batteryStats/fullAlign"
        # origin_path = "batteryStats/origin"

        strtegies_path = [fullAlign_path,align_path,paper_path,origin_path]



        for i in range(len(strategies_list)):
            print(strategies_list[i])
            for file_name in os.listdir(strtegies_path[i]):
                print(file_name + ": ")
                count_Walarm_Qpnp(os.path.join(strtegies_path[i], file_name))
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
